package com.ffe.flower.engine.dto;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.springframework.util.Assert;

public final class FlowDefinition {

  private String processId;

  private Enum<?> flowState;

  private boolean finished;

  private Map<Enum<?>, FlowDefinition> nexts = new HashMap<>();

  public boolean hasNext() {
    return !nexts.isEmpty();
  }

  private FlowDefinition() {
    super();
  }

  public FlowDefinition(String processId, Enum<?> flowState) {
    this(flowState);
    Assert.hasText(processId, "processId must not empty");
    this.processId = processId;
  }

  public FlowDefinition(Enum<?> flowState) {
    this(flowState, false);
  }

  public FlowDefinition(Enum<?> flowState, boolean finished) {
    this();
    Assert.notNull(flowState, "flowState must be not null");
    this.flowState = flowState;
    this.finished = finished;
  }

  public FlowDefinition addNext(Enum<?> event, FlowDefinition definition) {
    Assert.notNull(event, "event must be not null");
    Assert.notNull(definition, "definition must be not null");
    Assert.isTrue(!this.nexts.containsKey(event), "The event had already exist");
    // makeUpProcessId(definition);
    this.nexts.put(event, definition);
    return this;
  }

  private void makeUpProcessId(FlowDefinition definition) {
    definition.setProcessId(this.processId);
    if (definition.hasNext()) {
      for (FlowDefinition flowDefinition : definition.getNexts()) {
        definition.makeUpProcessId(flowDefinition);
      }
    }
  }

  public boolean isLast() {
    return !hasNext();
  }

  public FlowDefinition getNext(Enum<?> key) {
    return nexts.get(key);
  }

  public Enum<?> getFlowState() {
    return flowState;
  }

  public boolean isFinished() {
    return finished;
  }

  public void setFinished(boolean finished) {
    this.finished = finished;
  }

  public String getProcessId() {
    return processId;
  }

  public Collection<FlowDefinition> getNexts() {
    return Collections.unmodifiableCollection(nexts.values());
  }

  public void setProcessId(String processId) {
    Assert.hasText(processId, "processId must not empty");
    this.processId = processId;
  }

}
